#include "fileapi.h"

QXmlStreamReader readXml;
QXmlStreamWriter writeXml;


int saveAll(diagram* data,QFile &file)
{
	 writeXml.setDevice(&file);
     writeXml.setAutoFormatting(true);
     writeXml.writeStartDocument();
	 writeXml.writeStartElement("IDEFZER0");
	 saveDiagram(data);
	 writeXml.writeEndElement(); // IDEFZER0
     writeXml.writeEndDocument();
	return 0;
}

void saveDiagram(diagram* data)
{	 
		writeXml.writeStartElement("diagram");
			writeXml.writeAttribute("id", QString::number(data->id));
			writeXml.writeAttribute("name", data->name);
			writeXml.writeAttribute("max_id", QString::number(data->max_id));
			saveFrame(data->mFrame);
				QHashIterator<int,box*> iB(data->boxes);
				writeXml.writeStartElement("boxes");
				while (iB.hasNext()){
					saveBox(iB.next().value());
				}
				writeXml.writeEndElement(); // boxes
				
				QHashIterator<int,link*> iL(data->links);
				writeXml.writeStartElement("links");
				 while (iL.hasNext())  {
					saveLink(iL.next().value());
				 }
				writeXml.writeEndElement(); // links

				QHashIterator<int,diagram*> iC(data->children);
				writeXml.writeStartElement("children");
				 while (iC.hasNext())  {
					saveDiagram(iC.next().value());
				 }
				writeXml.writeEndElement(); // children
		writeXml.writeEndElement(); // diagram
}


void saveBox(box* b)
{
	writeXml.writeStartElement("box");
	writeXml.writeAttribute("id", QString::number(b->id));
	writeXml.writeAttribute("number", QString::number(b->number));
	writeXml.writeAttribute("x", QString::number(b->pos().x()));
	writeXml.writeAttribute("y", QString::number(b->pos().y()));
	writeXml.writeAttribute("height", QString::number(b->rect().height()));
	writeXml.writeAttribute("width", QString::number(b->rect().width()));
	writeXml.writeAttribute("name", b->name);
	if (b->child != NULL)
		writeXml.writeAttribute("child", QString::number(b->child->id));
	else
		writeXml.writeAttribute("child", QString("-1"));
	writeXml.writeAttribute("cost", QString::number(b->cost));
	writeXml.writeAttribute("cost_unit", b->cost_unit);
	writeXml.writeEndElement(); // box
}


void saveLink(link* lnk)
{
	writeXml.writeStartElement("link");
	writeXml.writeAttribute("id", QString::number(lnk->id));
	writeXml.writeAttribute("name", lnk->name);
	saveEnd(lnk->from);
	writeXml.writeStartElement("to");
		for (int i = 0; i < lnk->to.count(); i++)
			saveEnd(lnk->to.values()[i]);
	writeXml.writeEndElement(); // to
	writeXml.writeEndElement(); // link
}

void saveEnd(link::end* e){
	writeXml.writeStartElement("end");				
			writeXml.writeAttribute("flags",  QString::number(e->flags));
			if (e->b != NULL)
				writeXml.writeAttribute("box",  QString::number(e->b->id));
			else
				if (e->testEndFlag(link::TO_CONTEXT|link::TO_TUNNEL) )
					writeXml.writeAttribute("box",  QString("-1"));
				else
					writeXml.writeAttribute("box", QString("-2"));

			writeXml.writeAttribute("type",  QString::number(e->type));
			if (e->d != NULL)
				writeXml.writeAttribute("toDiagram",  QString::number(e->d->id));
			else
				writeXml.writeAttribute("toDiagram",  QString("-1"));

			if (e->next != NULL)
				writeXml.writeAttribute("nextPart",  QString::number(e->next->id));
			else
				writeXml.writeAttribute("nextPart",  QString("-1"));		
			saveSegmentPos(e->s);
	writeXml.writeEndElement(); // end
}


void saveSegmentPos(segment * s)
{
	writeXml.writeStartElement("segment");
	writeXml.writeAttribute("x1", QString::number(s->p1.x()));
	writeXml.writeAttribute("y1", QString::number(s->p1.y()));
	writeXml.writeAttribute("x2", QString::number(s->p2.x()));
	writeXml.writeAttribute("y2", QString::number(s->p2.y()));
	for (int i = 0; i < s->next.size(); i++){
		saveSegmentPos(s->next[i]);
	}
	writeXml.writeEndElement(); // segment
}
void saveFrame(frame *f){
	writeXml.writeStartElement("frame");
		writeXml.writeAttribute("purpose", QString::number(f->myPurpose));
		for (int i = 0; i < f->mapField.size(); i++)
			writeXml.writeAttribute(f->mapField.keys()[i], f->mapField[f->mapField.keys()[i]]->toPlainText());
	writeXml.writeEndElement(); // frame
}

#define ATTR( x ) readXml.attributes().value( x ).toString()


diagram *loadAll(QFile &file)
{
	readXml.setDevice(&file);
	readXml.readNextStartElement();

	if(readXml.isStartElement() && readXml.name() == "IDEFZER0")
	{
		readXml.readNextStartElement();
			return readDiagram();
	}
	return NULL;
}

link *readLink(diagram *parent){
	//qDebug() << "LINK";
	//qDebug() << "Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();
	if (readXml.name() != "link") return NULL;
	link *res	=	new link;

	res->id		=	ATTR("id").toInt();
	res->name	=	ATTR("name");
	

	readXml.readNextStartElement();

	if (readXml.name() == "end")
		res->from = readEnd();

	readXml.readNextStartElement();
	
	//qDebug() << "TO IN Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();

	if (readXml.name() == "to"){
		while (readXml.readNextStartElement()){
			
	//qDebug() << "TO END IN Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();

			if (readXml.name() == "end"){
				link::end *e = readEnd();
				res->to.insertMulti(e->b->id,e);
			}
			else readXml.skipCurrentElement();

	//qDebug() << "TO END OUT Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();
		}		
	}	
	else readXml.skipCurrentElement();
	//qDebug() << "TO OUT Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();

	res->annotation->setPlainText(res->name);
	res->annotation->setPos(res->from->s->p2);

	readXml.skipCurrentElement();
	//qDebug() << "LINK OUT Diagram#"<< parent->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();
	return res;
}

link::end* readEnd(){
	if (readXml.name() != "end") return NULL;
	link::end *res = new link::end(NULL,link::Output,NULL);
	qDebug() << "id" << ATTR("box");
	res->b = new box();
	res->b->id = ATTR("box").toInt();

	if (ATTR("toDiagram").toInt() >= 0)
		res->d = new diagram(ATTR("toDiagram").toInt());

	if (ATTR("nextPart").toInt() >= 0){
		res->next = new link();
		res->next->id = ATTR("nextPart").toInt();
	}	
	res->type = (link::ArrowType)(ATTR("type").toInt());
	res->flags = ATTR("flags").toInt();
	readXml.readNextStartElement();
		if (readXml.name() == "segment")
			res->s = readSegment();
	readXml.skipCurrentElement();
	return res;
}


box *readBox(){
	if (readXml.name() != "box") return NULL;
	box *res = new box;

	res->id			=	ATTR("id").toInt();
	res->number		=	ATTR("number").toInt();
	res->name		=	ATTR("name");
	res->cost		=	ATTR("cost").toInt();
	res->cost_unit	=	ATTR("cost_unit");
	
	res->setPos(QPointF(ATTR("x").toFloat(), ATTR("y").toFloat()));
	res->setRect(0,0, ATTR("width").toFloat(), ATTR("height").toFloat());
	if (ATTR("child").toInt() >=0 )
		res->child = new diagram(ATTR("child").toInt());
	
	readXml.skipCurrentElement();
	
	res->nameField = new diagramTextItem(QPointF(20,20), res->name, res);
	res->nameField->cutOffText();
	res->numberField = new diagramTextItem(QPointF(105, 60),QString("A%1").arg(res->number), res);
	res->costField = new diagramTextItem(QPointF(10, 60), QString("%1").arg(res->cost), res);	

	return res;
} 


void formEnd(link::end *e, diagram *d){
	if (e->b->id >= 0)
		e->b = d->boxes[e->b->id];
	else{
		delete e->b;
		e->b = NULL;
	}
	if (e->d != NULL){
		qDebug() << "Diagram #"<< d->id << "Children:" << d->children.keys();
		if ((d->parent) && (e->d->id == d->parent->id))
			e->d=d->parent;
		else
			e->d = d->children[e->d->id];
		e->next = e->d->links[e->next->id];
	}
}

diagram *readDiagram(diagram *parent){

	if (readXml.name() != "diagram") return NULL;
	diagram *res = new diagram;

	if(parent!=NULL) res->parent = parent;
	res->id		=	ATTR("id").toInt();
	res->name	=	ATTR("name");
	res->max_id	=	ATTR("max_id").toInt();

	qDebug() << "Diagram#"<< res->id;
	readXml.readNextStartElement();
	res->mFrame = readFrame(res);

	readXml.readNextStartElement();
	if (readXml.name() == "boxes"){
			while (readXml.readNextStartElement())
			if (readXml.name() == "box")
				res->boxes[ATTR("id").toInt()]=readBox();
			else readXml.skipCurrentElement();
		}

	readXml.readNextStartElement();

	if (readXml.name() == "links")
		while (readXml.readNextStartElement()){
			if (readXml.name() == "link")
				res->links[ATTR("id").toInt()]=readLink(res);
			else readXml.skipCurrentElement();
		}

	readXml.readNextStartElement();

	qDebug() << "Diagram#"<< res->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();
	if (readXml.name() == "children")
		while (readXml.readNextStartElement()){		
	qDebug() << "Diagram#"<< res->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();	

			if ((readXml.isStartElement()) && (readXml.name() == "diagram")){
				diagram *child = readDiagram(res);
				child->parent = res;
				res->children[child->id]=child;
			}
			else readXml.skipCurrentElement();
		}
	qDebug() << "Diagram#"<< res->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();
		
	readXml.skipCurrentElement();
	qDebug() << "Diagram#"<< res->id << "Token:" <<  readXml.name ()  <<  "Type:" << readXml.tokenString();

	qDebug() << "Diagram#"<< res->id << "Children:" << res->children.keys();


	QHashIterator<int,link*> iL(res->links);
	while(iL.hasNext()){
		link *lnk = iL.next().value();
		formEnd(lnk->from,res);
		if (lnk->from->b!= NULL)
			lnk->from->b->links.append(lnk);
		for (QHashIterator<int,link::end*> i(lnk->to); i.hasNext();){
			i.next();
			formEnd(i.value(),res);
			if ((i.value()->b != NULL) && (!i.value()->b->links.contains(lnk)))
				i.value()->b->links.append(lnk);
			}		
		res->addItem(lnk);
		lnk->update();
	}

	QHashIterator<int,box*> iB(res->boxes);
	while(iB.hasNext()){
		box *b = iB.next().value();
		res->addItem(b);
		if (b->child!=NULL){
			int cid = b->child->id;
			delete b->child;
			b->child = res->children[cid];
			b->pNodeField = new diagramTextItem(QPointF(100, 87), QString(""), iB.value());
			b->pNodeField->setPlainText(iB.value()->child->mFrame->mapField["Node"]->toPlainText());
			b->pNodeField->mText = iB.value()->child->mFrame->mapField["Node"]->toPlainText();
			b->correctNodeName();
		}
	}
	qDebug() << "LOADED";
	qDebug() << "Diagram:" << res->node();
	qDebug() << "Children count:" << res->children.count();
	return res;
}

segment *readSegment(){
	if (readXml.name() != "segment") return NULL;
	segment *res = new segment;
	
	res->p1 = QPointF(ATTR("x1").toFloat(), ATTR("y1").toFloat());
	res->p2 = QPointF(ATTR("x2").toFloat(), ATTR("y2").toFloat());	

		while (readXml.readNextStartElement()){
			if (readXml.name() == "segment"){
				res->next.append(readSegment());
				res->next.last()->prev = res;
			}
			else readXml.skipCurrentElement();
		}	
	return res;
}


frame * readFrame(diagram *parent){
	frame *res = new frame(ATTR("purpose").toInt(),NULL,parent);
	
	qDebug() << "Token: " <<  readXml.name ()  <<  "Type: " << readXml.tokenString();
	for (int i = 1; i < readXml.attributes().size(); i++){
		//qDebug() << "Attr: "<< readXml.attributes()[i].name().toString()<<" Value: " << readXml.attributes()[i].value().toString();
		res->mapField[readXml.attributes()[i].name().toString()]->setPlainText(readXml.attributes()[i].value().toString());
	}
	readXml.skipCurrentElement();
	return res;

}